package xyz.ibenben.zhongdian.system.service.impl;

import freemarker.template.Template;
import freemarker.template.TemplateException;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.core.io.FileSystemResource;
import org.springframework.mail.SimpleMailMessage;
import org.springframework.mail.javamail.JavaMailSender;
import org.springframework.mail.javamail.MimeMessageHelper;
import org.springframework.stereotype.Service;
import org.springframework.ui.freemarker.FreeMarkerTemplateUtils;
import org.springframework.util.StringUtils;
import org.springframework.web.servlet.view.freemarker.FreeMarkerConfigurer;
import xyz.ibenben.zhongdian.common.annotation.SystemServiceLog;
import xyz.ibenben.zhongdian.common.exception.ExceptionEnum;
import xyz.ibenben.zhongdian.common.exception.MyException;
import xyz.ibenben.zhongdian.common.util.RandomUtil;

import javax.annotation.Resource;
import javax.mail.MessagingException;
import javax.mail.internet.MimeMessage;
import java.io.File;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;

/**
 * 邮件发送服务类
 * 提供了一些基本的服务，如sendSimpleMail邮件记录、sendHtmlMail邮件记录等方法
 * 此类主要提供的是对发送邮件的服务，包括各种模板和简单邮件都可以使用此类
 *
 * @author chenjian
 * @since 2017年9月27日上午10:57:28
 */
@Service
public class EmailSenderService {
    /**
     * 自动注入的Bean
     */
    @Resource
    private JavaMailSender mailSender;
    /**
     * 自动注入
     */
    @Resource
    private FreeMarkerConfigurer freeMarkerConfigurer;

    @Value("${emailsender}")
    private String sender;

    /**
     * sendSimpleMail邮件记录
     *
     * @param reciver 参数
     * @param title   参数
     * @param text    参数
     */
    @SystemServiceLog(description = "sendSimpleMail邮件记录")
    public void sendSimpleMail(String reciver, String title, String text) {
        SimpleMailMessage message = new SimpleMailMessage();
        message.setFrom(sender);
        //自己给自己发送邮件
        message.setTo(reciver);
        message.setSubject(title);
        message.setText(text);
        mailSender.send(message);
    }

    /**
     * sendHtmlMail邮件记录
     *
     * @param reciver 参数
     * @param title   参数
     * @param sb      参数
     */
    @SystemServiceLog(description = "sendHtmlMail邮件记录")
    public void sendHtmlMail(String reciver, String title, StringBuilder sb) {
        try {
            MimeMessage message = mailSender.createMimeMessage();
            MimeMessageHelper helper = new MimeMessageHelper(message, true);
            helper.setFrom(sender);
            helper.setTo(reciver);
            helper.setSubject(title);
            helper.setText(sb.toString(), true);
            mailSender.send(message);
        } catch (MessagingException e) {
            throw new MyException(ExceptionEnum.SENDEMAILEXCEPTION, e);
        }
    }

    /**
     * sendInlineMail邮件记录
     *
     * @param reciver     参数
     * @param title       参数
     * @param contentHtml 参数
     * @param file        参数
     * @param filename    参数
     */
    @SystemServiceLog(description = "sendInlineMail邮件记录")
    public void sendInlineMail(String reciver, String title, String contentHtml, File file, String filename) {
        try {
            MimeMessage message = mailSender.createMimeMessage();
            MimeMessageHelper helper = new MimeMessageHelper(message, true);
            helper.setFrom(sender);
            helper.setTo(reciver);
            helper.setSubject(title);
            //第二个参数指定发送的是HTML格式,同时cid:是固定的写法
            helper.setText(contentHtml, true);

            FileSystemResource fsr = new FileSystemResource(file);
            helper.addInline(filename, fsr);
            mailSender.send(message);
        } catch (MessagingException e) {
            throw new MyException(ExceptionEnum.SENDEMAILEXCEPTION, e);
        }
    }

    /**
     * sendAttachmentsMail邮件记录
     *
     * @param reciver  参数
     * @param title    参数
     * @param content  参数
     * @param file     参数
     * @param filename 参数
     */
    @SystemServiceLog(description = "sendAttachmentsMail邮件记录")
    public void sendAttachmentsMail(String reciver, String title, String content, File file, String filename) {
        try {
            MimeMessage message = mailSender.createMimeMessage();
            MimeMessageHelper helper = new MimeMessageHelper(message, true);
            helper.setFrom(sender);
            helper.setTo(reciver);
            helper.setSubject(title);
            helper.setText(content);
            //注意项目路径问题，自动补用项目路径
            FileSystemResource fsr = new FileSystemResource(file);
            //加入邮件
            helper.addAttachment(filename, fsr);
            mailSender.send(message);
        } catch (MessagingException e) {
            throw new MyException(ExceptionEnum.SENDEMAILEXCEPTION, e);
        }
    }

    /**
     * sendTemplateMail邮件记录
     *
     * @param reciver  参数
     * @param title    参数
     * @param param    参数
     * @param filename 参数
     */
    @SystemServiceLog(description = "sendTemplateMail邮件记录")
    public void sendTemplateMail(String reciver, String title, Map<String, Object> param, String filename) {
        try {
            MimeMessage message = mailSender.createMimeMessage();
            MimeMessageHelper helper = new MimeMessageHelper(message, true);
            helper.setFrom(sender);
            helper.setTo(reciver);
            helper.setSubject(title);
            //读取 html 模板
            Template template = freeMarkerConfigurer.getConfiguration().getTemplate(filename);
            Map<String, Object> newParam = getNewMap(param);
            String html = FreeMarkerTemplateUtils.processTemplateIntoString(template, newParam);
            helper.setText(html, true);
            mailSender.send(message);
        } catch (MessagingException e) {
            throw new MyException(ExceptionEnum.SENDEMAILEXCEPTION, e);
        } catch (IOException e) {
            throw new MyException(ExceptionEnum.NOEMAILMODELEXCEPTION, e);
        } catch (TemplateException e) {
            throw new MyException(ExceptionEnum.PROCESSMODELEXCEPTION, e);
        }
    }

    /**
     * 获取新Map
     *
     * @param map 参数
     * @return 返回值
     */
    private Map<String, Object> getNewMap(Map<String, Object> map) {
        for (Map.Entry<String, Object> entry : map.entrySet()) {
            if (entry.getValue() == null) {
                entry.setValue("");
            }
        }
        return map;
    }

    /**
     * 发送重置密码邮件
     *
     * @param username 用户名
     * @param email    电子邮箱
     * @param index    索引
     * @param image    图片名称
     * @return 重新生成邮箱失效时间
     */
    @SystemServiceLog(description = "sendResetPasswordEmail邮件记录")
    public Map<String, Object> sendResetPasswordEmail(String username, String email, String index, String image) {
        String title = "房屋管理系统重置密码，请查收";
        String template = "resetpwd.ftl";

        Map<String, Object> param = new HashMap<>();
        param.put("username", StringUtils.isEmpty(username) ? email : username);
        param.put("index", index);
        param.put("title_image", image);
        String forgetPwdCode = RandomUtil.getRandomNumber(6);
        param.put("content", forgetPwdCode);

        Map<String, Object> result = new HashMap<>();
        result.put("forgetPwdCode", forgetPwdCode);
        result.put("verificationCodeTime", System.currentTimeMillis() / 1000 + Long.parseLong("3600"));

        this.sendTemplateMail(email, title, param, template);
        return result;
    }

    /**
     * 发送注册验证邮件
     *
     * @param username 用户名
     * @param email    电子邮箱
     * @param basePath 模板路径
     * @param image    图像名称
     */
    @SystemServiceLog(description = "sendRegistEmail邮件记录")
    public void sendRegistEmail(Long id, String username, String email, String basePath, String image) {
        String title = "房屋管理系统激活账号身份验证";
        String template = "regist.ftl";

        Map<String, Object> param = new HashMap<>();
        param.put("username", StringUtils.isEmpty(username) ? email : username);
        param.put("title_image", image);
        String url = basePath + "/emailActivate?userId=" + id + "&email=" + email;
        param.put("url", url);

        this.sendTemplateMail(email, title, param, template);
    }
}
